import base64
import copy
import json
import os
import uuid

from fastapi import FastAPI, Depends, HTTPException, status, Request, WebSocket, WebSocketDisconnect, File, Form, \
    UploadFile
from fastapi.security import OAuth2PasswordBearer
from fastapi.responses import JSONResponse
from fastapi.staticfiles import StaticFiles
from fastapi.responses import HTMLResponse, FileResponse
from fastapi.templating import Jinja2Templates
from typing import Union, Optional
from datetime import datetime, timedelta, timezone
import jwt
from mpmath.calculus.calculus import defun
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.middleware.cors import CORSMiddleware
from loguru import logger
from starlette.responses import StreamingResponse

from actions.category import category
from actions.goods import goods
from actions.attributes import attributes

from actions.config import cfg
from actions.dicts import dicts
from actions.role import role
from actions.tcp import Tcp
from actions.login import Login
from actions.user import user
from actions.menu import Menu

from actions.design import design

# 初始化 FastAPI 应用
app = FastAPI()
if not os.path.exists('data/overhaul_config'):
    os.makedirs('data/overhaul_config')


# 挂载目录为静态文件目录，访问路径前缀为 /images
# app.mount("/api/overhaul/config/pic", StaticFiles(directory="data/overhaul_config"), name="images")

class DynamicStaticMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request: Request, call_next):
        path = request.url.path
        print('path', path)
        if path.startswith("/api/static/pic"):
            parts = path.split("/")
            print(parts)
            file_path = os.path.join("data", parts[4], parts[5])
            print(file_path)
            if os.path.exists(file_path):
                return FileResponse(file_path)
        return await call_next(request)


# app.add_middleware(DynamicStaticMiddleware)

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)
# 保存所有连接的 WebSocket
connections = []
# 定义加密密钥和算法
SECRET_KEY = "your_secret_key"  # 这里建议用一个更安全的密钥
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 60

# OAuth2PasswordBearer 用于验证 OAuth2 token
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")


# 生成访问令牌的函数
def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None):
    to_encode = data.copy()
    if expires_delta:
        expire = datetime.now(timezone.utc) + expires_delta
    else:
        # 设置一个非常长的过期时间，比如 100 年
        expire = datetime.now(timezone.utc) + timedelta(days=36500)
        # expire = datetime.now(timezone.utc) + timedelta(minutes=15)
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt


# 自定义异常处理器
@app.exception_handler(HTTPException)
async def custom_http_exception_handler(request, exc: HTTPException):
    # 返回自定义格式的错误信息
    return JSONResponse(
        status_code=exc.status_code,
        content=exc.detail  # 返回detail本身，不再是嵌套结构
    )


# 获取当前用户的函数（验证 token）
async def get_current_user(token: str = Depends(oauth2_scheme)):
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        username: str = payload.get("sub")

        if username is None:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail={'msg': 'token验证失败', 'code': 401},
                headers={"WWW-Authenticate": "Bearer"}
            )
        return payload
    except jwt.PyJWTError:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,  # 修改为 400
            detail={'msg': 'token验证失败', 'code': 401},  # 返回更简洁的自定义错误格式
            headers={"WWW-Authenticate": "Bearer"},
        )


# 全局变量
server = Tcp()


# 配置日志
def setup_logger():
    if not os.path.exists('logs'):
        os.makedirs('logs')
    # 配置 loguru 日志记录
    log_filename = 'logs/' + 'log' + '.log'
    logger.add(
        log_filename,
        rotation="5 MB"
    )


templates = Jinja2Templates(directory="templates")


@app.get("/", response_class=HTMLResponse)
async def read_root(request: Request):
    return templates.TemplateResponse("index.html", {"request": request})


@app.get("/test1", response_class=HTMLResponse)
async def read_root(request: Request):
    return templates.TemplateResponse("video.html", {"request": request})


@app.get("/tt", response_class=HTMLResponse)
async def read_root(request: Request):
    return templates.TemplateResponse("video1.html", {"request": request})


@app.get("/yy", response_class=HTMLResponse)
async def read_root(request: Request):
    return templates.TemplateResponse("video2.html", {"request": request})



# 创建登录路由以生成Token
@app.post("/api/login")
async def loging(request: Request):
    data = await request.json()
    lg = Login()
    result, user_id, user_name = lg.login(data)
    print(result)
    if user_id is not None:
        access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
        access_token = create_access_token(
            data={"sub": str(user_id), 'userName': user_name}, expires_delta=access_token_expires
        )
        result['accessToken'] = access_token
    return result


# 获取人员信息
@app.get("/api/user/info")
async def user_info(request: Request, userInfo: str = Depends(get_current_user)):
    us = user()
    result = us.get_user_info(userInfo['sub'])
    return result


# 获取菜单
@app.get("/api/getRouters")
async def getRouters(request: Request, userInfo: str = Depends(get_current_user)):
    mn = Menu()
    print('userInfo', userInfo)
    result = mn.get_menu(userInfo['sub'])
    return result


# 返回所有菜单信息
@app.get("/api/system/menu/list")
async def menu_list(request: Request, userInfo: str = Depends(get_current_user)):
    mn = Menu()
    result = mn.get_menu_all()
    return result


# 增加菜单
@app.post('/api/system/menu')
async def system_menu_add(request: Request, userInfo: str = Depends(get_current_user)):
    data = await request.json()
    mn = Menu()
    result = mn.menu_add(data, userInfo)
    return result


# 修改菜单
@app.put('/api/system/menu')
async def system_menu_edit(request: Request, userInfo: str = Depends(get_current_user)):
    data = await request.json()
    mn = Menu()
    result = mn.menu_edit(data, userInfo)
    return result


# 删除菜单
@app.delete('/api/system/menu/{menuId}')
async def system_menu_del(menuId: str, userInfo: str = Depends(get_current_user)):
    print(menuId)
    mn = Menu()
    result = mn.menu_del(menuId)
    return result


# 角色一览
@app.get('/api/system/roles/list')
async def roles_list(request: Request, userInfo: str = Depends(get_current_user)):
    data = dict(request.query_params)
    rl = role()
    result = rl.get_role(data)
    return result


# 角色用户一览
@app.get('/api/system/role/authUser/allocatedList')
async def system_role_authUser_allocatedList(request: Request, userInfo: str = Depends(get_current_user)):
    data = dict(request.query_params)
    rl = role()
    result = rl.get_role_user(data)
    return result


# 获取角色下可分配的用户列表
@app.get('/api/system/role/authUser/unallocatedList')
async def system_role_authUser_unallocatedList(request: Request, userInfo: str = Depends(get_current_user)):
    data = dict(request.query_params)
    rl = role()
    result = rl.get_role_unallocatedList(data)
    return result


# 新增用户权限
@app.put('/api/system/role/authUser/selectAll')
async def system_role_authUser_selectAll(request: Request, userInfo: str = Depends(get_current_user)):
    data = dict(request.query_params)
    rl = role()
    result = rl.edit_user_role(data)
    return result


# 删除权限
@app.put('/api/system/role/authUser/cancelAll')
async def system_role_authUser_cancelAll(request: Request, userInfo: str = Depends(get_current_user)):
    data = dict(request.query_params)
    rl = role()
    result = rl.del_user_role(data)
    return result


# 新增角色
@app.post('/api/system/role')
async def system_role_add(request: Request, userInfo: str = Depends(get_current_user)):
    data = await request.json()
    rl = role()
    result = rl.role_add(data, userInfo)
    return result


# 修改角色
@app.put('/api/system/role')
async def system_role_edit(request: Request, userInfo: str = Depends(get_current_user)):
    data = await request.json()
    rl = role()
    result = rl.role_edit(data, userInfo)
    return result


# 删除角色
@app.delete('/api/system/role/{roleId}')
async def system_role_del(roleId: str, userInfo: str = Depends(get_current_user)):
    rl = role()
    result = rl.role_del(roleId, userInfo)
    return result


# 字典类型列表
@app.get('/api/system/dict/type/list')
async def dict_type_list(request: Request, userInfo: str = Depends(get_current_user)):
    data = dict(request.query_params)
    di = dicts()
    result = di.get_dict_type(data)
    return result


# 新增字典类型
@app.post('/api/system/dict/type')
async def system_dict_type_add(request: Request, userInfo: str = Depends(get_current_user)):
    data = await request.json()
    di = dicts()
    result = di.dict_type_add(data, userInfo)
    return result


# 修改字典类型
@app.put('/api/system/dict/type')
async def system_dict_type_edit(request: Request, userInfo: str = Depends(get_current_user)):
    data = await request.json()
    di = dicts()
    result = di.dict_type_edit(data, userInfo)
    return result


# 删除字典类型
@app.delete('/api/system/dict/type/{dictId}')
async def system_dict_type_del(dictId: str, userInfo: str = Depends(get_current_user)):
    di = dicts()
    result = di.dict_type_del(dictId)
    return result


# 字典数据列表
@app.get('/api/system/dict/data/list')
async def dict_data_list(request: Request, userInfo: str = Depends(get_current_user)):
    data = dict(request.query_params)
    di = dicts()
    result = di.get_dict_data(data)
    return result


# 获取字典数据
@app.get('/api/system/dict/data/type/{dictType}')
async def system_dict_data_type_list(dictType: str, userInfo: str = Depends(get_current_user)):
    di = dicts()
    result = di.get_dict_type_data(dictType)
    return result


# 新增字典数据
@app.post('/api/system/dict/data')
async def system_dict_data_add(request: Request, userInfo: str = Depends(get_current_user)):
    data = await request.json()
    di = dicts()
    result = di.dict_data_add(data, userInfo)
    return result


# 修改字典数据
@app.put('/api/system/dict/data')
async def system_dict_data_edit(request: Request, userInfo: str = Depends(get_current_user)):
    data = await request.json()
    di = dicts()
    result = di.dict_data_edit(data, userInfo)
    return result


# 修改字典数据
@app.delete('/api/system/dict/data/{dictCode}')
async def system_dict_data_del(dictCode: str, userInfo: str = Depends(get_current_user)):
    di = dicts()
    result = di.dict_data_del(dictCode)
    return result


# 参数列表
@app.get('/api/system/config/list')
async def config_list(request: Request, userInfo: str = Depends(get_current_user)):
    data = dict(request.query_params)
    cl = cfg()
    result = cl.get_config_data(data)
    return result


# 新增参数
@app.post('/api/system/config')
async def system_config_add(request: Request, userInfo: str = Depends(get_current_user)):
    data = await request.json()
    cl = cfg()
    result = cl.config_data_add(data, userInfo)
    return result


# 修改参数
@app.put('/api/system/config')
async def system_config_edit(request: Request, userInfo: str = Depends(get_current_user)):
    data = await request.json()
    cl = cfg()
    result = cl.config_data_edit(data, userInfo)
    return result


# 删除参数
@app.delete('/api/system/config/{configId}')
async def system_config_add(configId: str, userInfo: str = Depends(get_current_user)):
    cl = cfg()
    result = cl.config_data_del(configId)
    return result


# 查询单个参数
@app.get('/api/system/config/configKey/{configKey}')
async def system_config_configKey(configKey: str, userInfo: str = Depends(get_current_user)):
    cl = cfg()
    result = cl.get_config_configKey(configKey)
    return result


# 用户详情
@app.get('/api/system/user/info/{userId}')
async def userInfo(userId: int, userInfo: str = Depends(get_current_user)):
    us = user()
    result = us.get_userInfo(userId)
    return result


# 用户一览
@app.get('/api/system/user/list')
async def user_list(request: Request, userInfo: str = Depends(get_current_user)):
    # 将参数转换为字典
    data = dict(request.query_params)
    us = user()
    result = us.get_users(data)
    return result


# 新增用户
@app.post('/api/system/user')
async def system_user_add(request: Request, userInfo: str = Depends(get_current_user)):
    data = await request.json()
    us = user()
    result = us.user_add(data, userInfo)
    return result


# 修改用户
@app.put('/api/system/user')
async def system_user_edit(request: Request, userInfo: str = Depends(get_current_user)):
    data = await request.json()
    us = user()
    result = us.user_edit(data, userInfo)
    return result


# 重置密码
@app.put('/api/system/user/resetPwd')
async def system_user_resetPwd(request: Request, userInfo: str = Depends(get_current_user)):
    data = await request.json()
    us = user()
    result = us.user_resetPwd(data, userInfo)
    return result


# 删除用户
@app.delete('/api/system/user/{userId}')
async def system_user_del(userId: str, userInfo: str = Depends(get_current_user)):
    us = user()
    result = us.user_del(userId, userInfo)
    return result



# 商品分类列表
@app.get('/api/category/list')
async def category_info_list(request: Request, userInfo: str = Depends(get_current_user)):
    data = dict(request.query_params)
    cr = category()
    result = cr.get_category_list(data)
    return result


# 获取商品分类信息树形结构
@app.get('/api/category/tree')
async def category_tree_info(request: Request, userInfo: str = Depends(get_current_user)):
    data = dict(request.query_params)
    cr = category()
    result = cr.get_category_tree_info(data)
    return result


# 新增商品分类信息
@app.post('/api/category')
async def category_add(request: Request, userInfo: str = Depends(get_current_user)):
    data = await request.json()
    cr = category()
    result = cr.add_category(data, userInfo)
    return result


# 修改商品分类信息
@app.put('/api/category')
async def category_edit(request: Request, userInfo: str = Depends(get_current_user)):
    data = await request.json()
    cr = category()
    result = cr.edit_category(data, userInfo)
    return result


# 删除商品分类信息
@app.delete('/api/category/{categoryId}')
async def category_del(categoryId: str, userInfo: str = Depends(get_current_user)):
    cr = category()
    result = cr.del_category(categoryId, userInfo)
    return result


# 商品列表
@app.get('/api/goods/list')
async def goods_info_list(request: Request, userInfo: str = Depends(get_current_user)):
    data = dict(request.query_params)
    cr = goods()
    result = cr.get_goods_list(data)
    return result

# 新增商品信息
@app.post('/api/goods')
async def goods_add(request: Request, userInfo: str = Depends(get_current_user)):
    data = await request.json()
    cr = goods()
    result = cr.add_goods(data, userInfo)
    return result


# 修改商品信息
@app.put('/api/goods')
async def goods_edit(request: Request, userInfo: str = Depends(get_current_user)):
    data = await request.json()
    cr = goods()
    result = cr.edit_goods(data, userInfo)
    return result

# 查看商品信息
@app.get('/api/goods/{goodsId}')
async def goods_get(goodsId: str):
    cr = goods()
    result = cr.get_goods(goodsId)
    return result

# 删除商品信息
@app.delete('/api/goods/{goodsId}')
async def goods_del(goodsId: str, userInfo: str = Depends(get_current_user)):
    cr = goods()
    result = cr.del_goods(goodsId, userInfo)
    return result


# 属性列表
@app.get('/api/attribute/list')
async def attribute_info_list(request: Request, userInfo: str = Depends(get_current_user)):
    data = dict(request.query_params)
    cr = attributes()
    result = cr.get_attribute_list(data)
    return result

# 新增属性信息
@app.post('/api/attribute')
async def attribute_add(request: Request, userInfo: str = Depends(get_current_user)):
    data = await request.json()
    cr = attributes()
    result = cr.add_attribute(data, userInfo)
    return result


# 修改属性信息
@app.put('/api/attribute')
async def attribute_edit(request: Request, userInfo: str = Depends(get_current_user)):
    data = await request.json()
    cr = attributes()
    result = cr.edit_attribute(data, userInfo)
    return result


# 删除属性信息
@app.delete('/api/attribute/{attributeId}')
async def attribute_del(attributeId: str, userInfo: str = Depends(get_current_user)):
    cr = attributes()
    result = cr.del_attribute(attributeId, userInfo)
    return result



# 文件上传
@app.post('/api/file/upload/{path}')
async def upload_file(path: str, file: UploadFile = File(...)):
    result = {'msg': '文件保存成功', 'code': 200, 'addr': ''}
    if file:
        # 读取文件内容
        content = await file.read()
        file_path = path
        _ = file.filename.split('.')
        if _[-1] != 'mp3':
            filename = uuid.uuid4().hex + '.' + _[-1]
            if not os.path.exists(f"data/{file_path}"):
                os.makedirs(f"data/{file_path}")
            # 将文件保存到本地
            file_location = f"data/{file_path}/{filename}"
            with open(file_location, "wb") as f:
                f.write(content)
            result['addr'] = f'/static/pic/{file_path}/{filename}'
        else:
            filename = 'audio.' + _[-1]
            if not os.path.exists(f"data/{file_path}"):
                os.makedirs(f"data/{file_path}")
            # 将文件保存到本地
            file_location = f"data/{file_path}/{filename}"
            with open(file_location, "wb") as f:
                f.write(content)
            result['addr'] = f'data/{file_path}/{filename}'
    else:
        result['code'] = 500
        result['msg'] = '文件上传失败'
    return result


# WebSocket连接
@app.websocket("/main")
async def websocket_endpoint(websocket: WebSocket):
    global server
    await websocket.accept()
    # 将新连接添加到列表中
    connections.append(websocket)
    cmd = server.get_yy_num()
    for wb in connections:
        # 尝试发送消息，如果连接断开则会触发异常
        await wb.send_text(json.dumps(cmd))
    try:
        while True:
            # print('connections', connections)
            data = await websocket.receive_text()
            # print(data)
            data = json.loads(data)
            ss = copy.deepcopy(data)
            if data['type'] != 'heartbeat':
                update_img_field(ss)
                logger.info(f"webscokets接收消息：{ss}")
            await server.web_handle(data, websocket, connections)
    except WebSocketDisconnect as e:
        # 连接断开时从列表中移除
        connections.remove(websocket)
        logger.info(f"WebSocket 连接断开：{e.code}")
        print(f"当前连接：{connections}")
        logger.info(f"当前连接数：{len(connections)}")


def update_img_field(data):
    if isinstance(data, dict):  # 如果是字典
        for key, value in data.items():
            if key == "img":
                data[key] = ''  # 修改img字段为''
            else:
                update_img_field(value)  # 递归处理子字段
    elif isinstance(data, list):  # 如果是列表
        for item in data:
            update_img_field(item)  # 递归处理列表中的每一项


# 启动FastAPI应用
if __name__ == "__main__":
    import uvicorn

    setup_logger()
    uvicorn.run(app, host="0.0.0.0", port=8880)
